package com.example.gobang.game;

import com.example.gobang.GobangApplication;
import com.example.gobang.mapper.UserMapper;
import com.example.gobang.model.GameRequest;
import com.example.gobang.model.GameResponse;
import com.example.gobang.model.User;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;

import java.io.IOException;
import java.util.UUID;
@Slf4j

public class Room {
    private String roomId;
    private User user1;
    private User user2;
    private int blackUser;

    private OnlineUserManager userManager;
    private RoomManager roomManager;
    private UserMapper userMapper;

    private final ObjectMapper objectMapper = new ObjectMapper();
    private final static int MAX_ROW = 15;
    private final static int MAX_COL = 15;
    private final int[][] board = new int[MAX_ROW][MAX_COL];
    // 0 表示当前位置为落子，1表示 user1 的落子， 2表示 user2 的落子
    public Room(){
        userManager = GobangApplication.context.getBean(OnlineUserManager.class);
        roomManager = GobangApplication.context.getBean(RoomManager.class);
        userMapper = GobangApplication.context.getBean(UserMapper.class);
        roomId = UUID.randomUUID().toString();
    }


    /**
     * 处理一次落子请求 并进行胜负判定 为所有玩家返回响应
     * @param jsonString 前段传递的落子请求
     */
    public void putChess(String jsonString) throws IOException {
        GameRequest request = objectMapper.readValue(jsonString, GameRequest.class);
        GameResponse response = new GameResponse();
        int chess = request.getUserId() == user1.getUserId() ? 1 : 2;

        int row = request.getRow();
        int col = request.getCol();
        if(board[row][col] != 0){
            log.info("当前位置已经有棋子");
        }
        // 打印棋盘内容
        board[row][col] = chess;
        printBoard(request);
        int winner = checkWinner(row, col, chess);
        response.setMessage("putChess");
        response.setUserId(request.getUserId());
        response.setRow(row);
        response.setCol(col);
        response.setWinner(winner);
        // 为每个用户返回响应
        WebSocketSession user1Session = userManager.getOnlineRoom(user1.getUserId());
        WebSocketSession user2Session = userManager.getOnlineRoom(user2.getUserId());
        if(user1Session == null){
            response.setWinner(user2.getUserId());
            log.info("玩家 " + user1.getUsername() + " 掉线");
        }
        if(user2Session == null){
            response.setWinner(user1.getUserId());
            log.info("玩家 " + user2.getUsername() + " 掉线");
        }
        String respJson = objectMapper.writeValueAsString(response);
        if(user1Session != null) {
            user1Session.sendMessage(new TextMessage(respJson));
        }
        if(user2Session != null){
            user2Session.sendMessage(new TextMessage(respJson));
        }
        if(winner != -1){
            //游戏已经分出胜负
            if(winner == user1.getUserId()){
                userMapper.winUser(user1.getUserId());
                userMapper.loseUser(user2.getUserId());
            } else {
                userMapper.winUser(user2.getUserId());
                userMapper.loseUser(user1.getUserId());
            }
            log.info("游戏结束，销毁房间 " + (winner == user1.getUserId() ? user1.getUsername() : user2.getUsername()) + " 获胜");
            roomManager.remove(roomId, user1.getUserId(), user2.getUserId());
        }
    }

    private void printBoard(GameRequest request) {
        log.info("打印棋盘落子情况");
        boolean flag = request.getUserId() == user1.getUserId();
        if(flag){
            System.out.println(user1.getUsername() + " 落黑子");
        } else {
            System.out.println(user2.getUsername() + " 落白子");
        }
        System.out.println("==================================");
        for(int i = 0; i < MAX_ROW; i++){
            for (int j = 0; j < MAX_COL; j++) {
                System.out.print(board[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println("==================================");
    }

    /**
     * 判断是否决出胜负
     * @param row
     * @param col
     * @return 玩家 1 获胜 返回玩家 1 的userId，
     * 玩家 2 获胜 返回玩家 2 的userId 否则返回 0
     */
    private int checkWinner(int row, int col, int chess) {
        for (int i = col - 4; i <= col ; i++) {
            try {
                if (board[row][i] == chess && board[row][i + 1] == chess
                        && board[row][i + 2] == chess && board[row][i + 3]
                        == chess && board[row][i + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        for (int j = row - 4; j <= row ; j++) {
            try {
                if (board[j][col] == chess && board[j + 1][col] == chess
                        && board[j + 2][col] == chess && board[j + 3][col]
                        == chess && board[j + 4][col] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        for (int i = row - 4, j = col - 4; i <= row && j <= col; i++, j++) {
            try {
                if (board[i][j] == chess && board[i + 1][j + 1] == chess
                        && board[i + 2][j + 2] == chess && board[i + 3][j + 3]
                        == chess && board[i + 4][j + 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        for (int i = row - 4, j = col + 4; i <= row && j >= col; i++, j--) {
            try {
                if (board[i][j] == chess && board[i + 1][j - 1] == chess
                        && board[i + 2][j - 2] == chess && board[i + 3][j - 3]
                        == chess && board[i + 4][j - 4] == chess) {
                    return chess == 1 ? user1.getUserId() : user2.getUserId();
                }
            } catch (ArrayIndexOutOfBoundsException e){
                continue;
            }
        }
        // TODO 判断和棋
        return -1;
    }

    public int getBlackUser() {
        return blackUser;
    }

    public void setBlackUser(int blackUser) {
        this.blackUser = blackUser;
    }

    public String getRoomId() {
        return roomId;
    }

    public void setRoomId(String roomId) {
        this.roomId = roomId;
    }

    public User getUser1() {
        return user1;
    }

    public void setUser1(User user1) {
        this.user1 = user1;
    }

    public User getUser2() {
        return user2;
    }

    public void setUser2(User user2) {
        this.user2 = user2;
    }
}
